package com.chuangyiruanke.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.*;

import static java.util.concurrent.TimeUnit.NANOSECONDS;

/**
 * 表示按队列方式顺序执行任务的执行器。
 */
public class QueueExecutor {
    private boolean stopped;
    private final String name;
    private final BlockingQueue<QueueTask> messageQueue;
    private static final Logger logger = LoggerFactory.getLogger(QueueExecutor.class);

    private static final EmptyTask EMPTY_TASK = new EmptyTask();

    /**
     * 获取执行器名称。
     */
    public String getName() {
        return name;
    }

    /**
     * 执行器是否已停止运行。
     */
    public boolean isStopped() {
        return stopped;
    }

    /**
     * 创建新的队列执行器。
     *
     * @param name 执行器名称。
     */
    public QueueExecutor(String name) {
        this(name, 200);
    }

    /**
     * 创建新的队列执行器。
     *
     * @param name      执行器名称。
     * @param queueSize 队列大小。
     */
    public QueueExecutor(String name, int queueSize) {
        this.name = name;
        this.messageQueue = getQueueContainer(queueSize);
        logger.debug("getQueueContainer 返回: {}", this.messageQueue);
    }

    /**
     * 开始执行任务。
     */
    public void beginExecute() {
        logger.debug("启动[{}]线程！", name);
        new Thread(() -> {
            while (true) {
                QueueTask task = null;
                try {
                    task = this.takeNext();
                    logger.debug("[{}]任务已获取：[{}]！", name, task);
                    if (task == EMPTY_TASK) {
                        break;
                    }
                    this.runTask(task);
                } catch (InterruptedException ex) {
                    logger.warn(ex.getMessage(), ex);
                    logger.debug("[{}]执行任务[{}]结果：终止！", name, task);
                    break;
                } catch (Exception ex) {
                    logger.debug("执行[{}]任务[{}]结果：失败！", name, task);
                    try {
                        if (task != null) {
                            task.onError(this);
                        }
                        logger.error(ex.getMessage(), ex);
                    } catch (Exception e) {
                        logger.error(ex.getMessage(), ex);
                    }
                }
            }
            this.stopped = true;
            logger.info("[{}]线程已停止！", name);
        }).start();
        logger.info("[{}]线程已启动！", name);
    }

    /**
     * 获取队列容器。
     *
     * @param queueSize 队列大小
     * @return 队列容器（默认使用{@link ArrayBlockingQueue}）。
     */
    protected BlockingQueue<QueueTask> getQueueContainer(int queueSize) {
        return new ArrayBlockingQueue<>(queueSize);
    }

    /**
     * 向执行队列中添加执行任务。
     *
     * @param task 执行任务。
     */
    public void push(QueueTask task) {
        try {
            if (this.stopped) {
                return;
            }
            logger.debug("[{}]添加任务[{}]！", name, task);
            this.messageQueue.put(task);
            logger.debug("[{}]添加任务[{}]成功！", name, task);
        } catch (InterruptedException ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    protected void runTask(QueueTask task) throws Exception {
        logger.debug("[{}]执行任务[{}]！", name, task);
        task.run();
        logger.debug("[{}]执行任务[{}]，结果：成功！", name, task);
    }

    /**
     * 停止执行任务。
     */
    public void stopExecute() {
        logger.debug("[{}]请求停止任务！", name);
        try {
            this.messageQueue.put(EMPTY_TASK);
            logger.debug("[{}]停止任务请求已发送！", name);
        } catch (InterruptedException ex) {
            logger.error(ex.getMessage(), ex);
        }
    }

    /**
     * 清空并停止所有执行任务。
     */
    public void stopNow() {
        logger.debug("[{}]清空任务队列！", name);
        this.messageQueue.clear();
        stopped = true;
        this.stopExecute();
    }

    protected final QueueTask takeNext() throws InterruptedException {
        logger.debug("[{}]开始获取下一任务！", name);
        QueueTask task = this.messageQueue.take();
        if (task != EMPTY_TASK) {
            return processWhenAcquire(task);
        } else {
            return task;
        }
    }

    protected QueueTask processWhenAcquire(QueueTask task) {
        return task;
    }

    private static class EmptyTask implements QueueTask {
        @Override
        public void run() throws Exception {
        }

        @Override
        public void onError(QueueExecutor executor) {
        }

        @Override
        public String toString() {
            return "[终止执行]";
        }
    }

    /**
     * 任务。
     */
    public interface QueueTask extends Delayed {
        /**
         * 运行任务。
         */
        void run() throws Exception;

        /**
         * 任务失败时回调。
         *
         * @param executor 任务执行器。
         */
        void onError(QueueExecutor executor);

        @Override
        default long getDelay(TimeUnit unit) {
            return 0;
        }

        @Override
        default int compareTo(Delayed o) {
            if (o == this) return 0;
            long diff = getDelay(NANOSECONDS) - o.getDelay(NANOSECONDS);
            return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
        }
    }
}
